import java.util.ArrayList;
import java.awt.event.*;

class Area
{
	public int[][] cells;
	private int areaSize = 10;
	private String[] alphabet = Tools.alphabet;
	private ArrayList<Ship> ships = new ArrayList<Ship>();
	private Map map;
	private int[] allowedShipsQuantity;
	private boolean isAI = false;
	
	public Area()
	{
		make();
	}
	
	public Object getProps()
	{
		ArrayList<Object> props = new ArrayList<Object>();

		props.add(cells);
		props.add(ships);
		props.add(areaSize);
		
		return props;
	}
	
	public void isAI(boolean value)
	{
		isAI = value;
	}
	
	public boolean isAI()
	{
		return isAI;
	}
	
	public int[][] getCells()
	{
		return cells;
	}
	
	public void setMap(Map map)
	{
		this.map = map;
	}
	
	public Map getMap()
	{
		return map;
	}
	
	public boolean coordIsShot(String coord)
	{
		int[] coords = Tools.convertStringCoordsToInt(coord);

		if (cells[coords[0]][coords[1]] == -2 || 
			cells[coords[0]][coords[1]] == -1) { return true; }
		else {return false; }
	}
	
	public void reset()
	{
		make();
		ships = new ArrayList<Ship>();
	}
	
	public ArrayList<Ship> getShips()
	{
		return ships;
	}
	
	public void occupyCell(int coordX, int coordY)
	{
		
		MyButton cellButton = map.getButtonByCoords(coordX, coordY);
		Control control = Control.getInstance();
			
		if (cellIsAvailable(coordX, coordY))
		{
			ArrayList<String> neighbourCells = scanCellNeighbours(coordX, coordY);
			String coord = alphabet[coordX] + Integer.toString(coordY);
			int[] shipsSufficiency = checkShipsSufficiency();
			
			if (!cellIsOccupied(coordX, coordY))
			{
				switch (neighbourCells.size())
				{
					case 0:
						if (shipsSufficiency[0] == 0)
						{
							ships.add(new Ship(coord));
							cells[coordX][coordY] = 1;
							cellButton.occupy();
						}
						else
						{
							control.displayMessage("You have already placed 4 of one-deck ships\nAt first remove one of them");
							cellButton.red();
						}
						
						break;
					case 1:

						Ship ship = getShipByCoord(neighbourCells.get(0).toString());
						
						if (ship.getDecks() < 4)
						{	
							if (shipsSufficiency[ship.getDecks()] == 0)
							{
								ship.setCoord(coord);
								cells[coordX][coordY] = 1;
								cellButton.occupy();
							}
							else
							{
								control.displayMessage("As a result of adding cell to the ship you will get another" + (ship.getDecks() + 1) + " deck ship. But you have already placed" + countShips()[ship.getDecks()] +  " of one-deck ships\n");
								cellButton.red();
							}
						}
						else
						{	
							control.displayMessage("You can't have a five-deck ship");
							cellButton.red();
						}
						break;
					case 2:
						Ship ship1 = getShipByCoord(neighbourCells.get(0).toString());
						Ship ship2 = getShipByCoord(neighbourCells.get(1).toString());
						int decks  = ship1.getDecks() + ship2.getDecks();
						
						
						if (decks < 4)
						{
							int checkShipsSufficiency = shipsSufficiency[decks];
							
							if (checkShipsSufficiency == 0)
							{
								ship = new Ship(coord);
								cells[Tools.convertStringCoordsToInt(coord)[0]][Tools.convertStringCoordsToInt(coord)[1]] = 1;
								cellButton.occupy();
								
								@SuppressWarnings("unchecked")
								ArrayList<String> ship1Coords = (ArrayList<String>) ship1.getCoords().clone();
								@SuppressWarnings("unchecked")
								ArrayList<String> ship2Coords = (ArrayList<String>) ship2.getCoords().clone();
								
								String[] shipsCoords = {neighbourCells.get(0).toString(), neighbourCells.get(1).toString()};
								removeShipByCoord(shipsCoords[0]);
								removeShipByCoord(shipsCoords[1]);
								
								for (Object shipCoord : ship1Coords)
								{	
									ship.setCoord(shipCoord.toString());
									cells[Tools.convertStringCoordsToInt(shipCoord.toString())[0]][Tools.convertStringCoordsToInt(shipCoord.toString())[1]] = 1;
								}
								
								for (Object shipCoord : ship2Coords)
								{
									shipCoord = shipCoord.toString();
									ship.setCoord(shipCoord.toString());
									cells[Tools.convertStringCoordsToInt(shipCoord.toString())[0]][Tools.convertStringCoordsToInt(shipCoord.toString())[1]] = 1;
								}
								

								ships.add(ship);
							}
							else
							{
								control.displayMessage("You can't join these two ships. Because you already have " + countShips()[decks] + " of " + (decks + 1) + ships);
								cellButton.red();
							}
						}
						else
						{
							control.displayMessage("You can't join these two ships into a five-deck ship");
							cellButton.red();
						}
						break;
				}
			}
			else
			{		
				Ship foundShip = getShipByCoord(coord);
				
				switch (neighbourCells.size())
				{
					case 0:					
						removeShipByCoord(coord);
						cells[coordX][coordY] = 0;
						cellButton.occupy();
						break;
					case 1:			
						if (shipsSufficiency[foundShip.getDecks() - 2] == 0)
						{
							foundShip.removeCoord(coord);
							cells[coordX][coordY] = 0;
							cellButton.occupy();
						}
						else
						{
							control.displayMessage("You can't make this ship smaller, because you already have " + countShips()[foundShip.getDecks() - 2] + " of " + (foundShip.getDecks() - 1) + " ships");
							cellButton.red();
						}
						break;
					case 2:
						
						if (shipsSufficiency[0] == 0)
						{
							if (foundShip.getDecks() == 4 && shipsSufficiency[1] == 1)
							{
								control.displayMessage("You can't divide this ship into two smaller ships, because you already have " + countShips()[1] + " of two-deck ships");
								cellButton.red();
								break;
							}
						
							removeShipByCoord(coord);
							cells[coordX][coordY] = 0;
							cellButton.occupy();
							Ship ship1 = new Ship();
							Ship ship2 = new Ship();
							
							ArrayList<ArrayList<String>> splitCoords = findAllOccupiedCellsInDirection(coordX, coordY);
							
							ArrayList<String> splitCoords1 = splitCoords.get(0);
							ArrayList<String> splitCoords2 = splitCoords.get(1);
							
							for (Object splitCoord1 : splitCoords1)
							{	
								ship1.setCoord(splitCoord1.toString());
							}
							
							for (Object splitCoord2 : splitCoords2)
							{	
								ship2.setCoord(splitCoord2.toString());
							}
							
							ships.add(ship1);
							ships.add(ship2);
						}
						else
						{
							cellButton.red();
							control.displayMessage("You can't divide this ship into two smaller ships, because you already have " + countShips()[1] + " of one-deck ships");
						}
						
						break;
					
				}
				
			}	
		}
		else
		{
			cellButton.red();
			control.displayMessage("This cell is not available!");
		}	
		
		int[] shipsByRang = countShips();
		
		control.displayShipsQty(shipsByRang);
	}
	
	private Ship getShipByCoord(String coord)
	{
		for (Ship ship : ships)
		{
			ArrayList<String> coords = ship.getCoords();

			if (coords.contains(coord)) return ship;
		}
		
		return null;
	}
	
	private void removeShipByCoord(String coord)
	{	
		for (Ship ship : ships)
		{
			if (ship.getCoords().contains(coord)) 
			{
				ships.remove(ship);
				break;
			}
		}
	}
	
	public int shoot(String coord)
	{
		int result;
		System.out.println("<<<<<<Shooting!");
		System.out.println("Coord" + coord);
		int[] coords = Tools.convertStringCoordsToInt(coord);
		Ship ship = getShipByCoord(coord);
		
		if (ship == null)
		{
			System.out.println("No ship in the location");
			result = 0;
			cells[coords[0]][coords[1]] = -2;
		}
		else
		{
			result = ship.shot(coord);
			cells[coords[0]][coords[1]] = -1;
			
			if (result == -1)
			{
				ships.remove(ship);
				System.out.println("Ship's removed");
			}
		}
		
		return result;
	}
	
	private int[] countShips()
	{
		int i, j;
		int[] shipsByRang = new int[4];
		
		if (!ships.isEmpty())
		{
			for (Ship ship : ships)
			{
				int rang = ship.getCoords().size() - 1;
				shipsByRang[rang]++;
			}
		}
		
		return shipsByRang;
	}
	
	public int[] checkShipsSufficiency()
	{
		int[] shipsByRang = countShips();
		int[] shipsCeil = {0, 0, 0, 0};
		int allowedQty = 0;
		
		for (int i = 0; i < shipsByRang.length; i++)
		{
			allowedQty = 4 - i;
			/*
			System.out.println("Checking sufficiency...");
			System.out.println("AlowedQty:" + allowedQty);
			System.out.println("Decks:" + (i + 1));
			System.out.println("Qty:" + shipsByRang[i]);
			System.out.println("=======================");*/
			
			
			if (allowedQty == shipsByRang[i])
			{
				shipsCeil[i] = 1;
			}
		}
		
		return shipsCeil;
	}
	
	public String findProperAim()
	{
		System.out.println("Searching for a proper aim");
		AI ai = AI.getInstance();
		System.out.println("Coord in mind: " + ai.coordInMind());
	
		int condition = 0;
		String coord;
		
		if (ai.coordInMind() == null)
		{
			int coordXRand;
			int coordYRand;
			String coordRand = null;
		
			while (condition != 2)
			{
				condition = 0;
				
				coordXRand = getRandomCoord();
				coordYRand = getRandomCoord();
				coordRand  = Tools.convertIntCoordsToString(coordXRand, coordYRand);
				
				System.out.println("Trying rand coord: " + Tools.convertIntCoordsToString(coordXRand, coordYRand));
				System.out.println("Cells vacant: " + cells[coordXRand][coordYRand]);
				
				if (!coordIsShot(coordRand))
				{
					condition++;
				}
				
				if (cellCanBeShot(coordRand, null)) { condition++; }
			}
			
			condition = 0;
			
			coord = coordRand;
		}
		else
		{	
			if (ai.finishHim() || endOfAreaFound())
			{
				Ship ship = getShipByShotCoord(ai.coordInMind());
				ArrayList<String> shipCoords = ship.getCoords();
				coord = shipCoords.get(shipCoords.size() - 1).toString();
			}
			else 
			{
				coord = coordToSink(ai.coordInMind());
			}
		}
		
		return coord;
	}
	
	private boolean endOfAreaFound()
	{
		System.out.println("Checking the end of area");
		AI ai = AI.getInstance();
		ArrayList<String> coords = ai.coordsInMind();
		
		boolean endOfArea = false;
		System.out.println("Coords in mind: " + coords);
		System.out.println("size:" + coords.size());
		
		if (coords.size() > 1)
		{
			System.out.println("In mind we keep " + coords.size() + " coords");
		
			String coord1 = coords.get(coords.size() - 1).toString();
			String coord2 = coords.get(coords.size() - 2).toString();
			int[] coords1 = Tools.convertStringCoordsToInt(coord1);
			int[] coords2 = Tools.convertStringCoordsToInt(coord2);
			int x1 = coords1[0];
			int x2 = coords2[0];
			int y1 = coords1[1];
			int y2 = coords2[1];
			
			int direction = findDirectionByCoords(coord1, coord2);
			
			System.out.println("The direction is " + direction);
			
			switch (direction)
			{
				case 0:
					if ((x1 - 1) < 0 || (x2 - 1) < 0)
						endOfArea = true;
						
					break;
					
				case 1:
					if ((y1 - 1) < 0 || (y2 - 1) < 0)
						endOfArea = true;
						
					break;
					
				case 2:
					if ((x1 + 1) > 9 || (x2 + 1) > 9)
						endOfArea = true;
						
					break;
				
				case 3:
					if ((y1 + 1) > 9 || (y2 + 1) > 9)
						endOfArea = true;
						
					break;
			}
		}
		
		System.out.println("EndOfAreaFound: " + endOfArea);
		
		return endOfArea;
	}
	
	private Ship getShipByShotCoord(String coord)
	{
		for (Ship ship : ships)
		{
			ArrayList<String> coords = ship.getShotCoords();

			if (coords.contains(coord)) return ship;
		}
		
		return null;
	}
	
	public void locateShipsRandom()
	{	
		reset();
	
		int decks;
		int number = 1;
		
		for (decks = 4; decks > 0; decks--)
		{
			int k;
			
			for (k = 0; k < number; k++)
			{
				while (true)
				{
					int x = getRandomCoord();
					int y = getRandomCoord();
					int direction = (int) (Math.random() * 2);
					
					if (cells[x][y] == 0)
					{
						if (direction == 1)
						{
							if ((x + decks + 1) != 1 && (x + decks + 1) < (this.areaSize - 1))
							{
								if (checkShipNeighbourCells(x, y, decks, direction) == true)
								{
									
									int i;
									
									Ship ship = new Ship();
									ships.add(ship);
									
									for (i = 0; i < decks; i++)
									{
										
										int j = x + i;
										cells[j][y] = 1;
										
										ship.setCoord(alphabet[j] + Integer.toString(y));
									}
									
									break;
								}
							}
						}  
						else 
						{
							if (y + decks + 1 != 1 && y + decks + 1 < (this.areaSize - 1))
							{
								if (checkShipNeighbourCells(x, y, decks, direction) == true)
								{
									Ship ship = new Ship();
									ships.add(ship);
									int i;
									
									for (i = 0; i < decks; i++)
									{
										int j = y + i;
										cells[x][j] = 1;
										
										ship.setCoord(alphabet[x] + Integer.toString(j));
										
									}
									
									break;
								}
							}
						}
					}
				}
			}
			
			number++;
		}
		
		int[] shipsByRang = countShips();
		/*
		System.out.println("4 decks:" + shipsByRang[3]);
		System.out.println("3 decks:" + shipsByRang[2]);
		System.out.println("2 decks:" + shipsByRang[1]);
		System.out.println("1 decks:" + shipsByRang[0]);*/
	}
	
	private boolean checkShipNeighbourCells(int coordX, int coordY, int decks, int direction)
	{
		boolean result = false;

		for (int i = 0; i < decks; i++)
		{	
			int x, y;
		
			if (direction == 1)
			{
				x = coordX + i;
				y = coordY;
			}
			else
			{
				x = coordX;
				y = coordY + i;
			}

			if (x >= 0 && x <= 9 && y >= 0 && y <= 9)
			{
				if (cellIsAvailable(x, y) == true && scanCellNeighbours(x, y).size() == 0)
				{
					result = true;
				}
				else
				{
					result = false;
					break;
				}
			}
		}
		
		return result;
	}
	
	private void make()
	{
		int i;
		
		cells = new int[10][10];
	
		for (i = 0; i < areaSize; i++)
		{
			int j;
		
			for (j = 0; j < areaSize; j++)
			{
				cells[i][j] = 0;
			}
		}
	}
	
	public int getRandomCoord()
	{
		return ((int) (Math.random() * this.areaSize));
	}
	
	public int findDirectionByCoords(String coord1, String coord2)
	{
		int[] coords1 = Tools.convertStringCoordsToInt(coord1);
		int[] coords2 = Tools.convertStringCoordsToInt(coord2);
		
		int x1 = coords1[0];
		int x2 = coords2[0];
		int y1 = coords1[1];
		int y2 = coords2[1];
		
		int direction = -1;
		
		if ((x2 - 1) == x1)
		{
			direction = 0;
		}
		
		if ((y2 - 1) == y1)
		{
			direction = 1;
		}
		
		if ((x2 + 1) == x1)
		{
			direction = 2;
		}
		
		if ((y2 + 1) == y1)
		{
			direction = 3;
		}
		
		return direction;
	}
	
	public boolean cellIsAvailable(int x, int y)
	{
		if (x > 0 && y < 9 && cells[x - 1][y + 1] == 1) return false; 
		if (x < 9 && y < 9 && cells[x + 1][y + 1] == 1) return false; 
		if (y > 0 && x > 0 && cells[x - 1][y - 1] == 1) return false; 
		if (y > 0 && x < 9 && cells[x + 1][y - 1] == 1) return false; 
		
		return true;
	}
	
	private boolean cellIsOccupied(int x, int y)
	{
		if (cells[x][y] == 1) return true;
		
		return false;
	}
	
	private ArrayList<String> scanCellNeighbours(int x, int y)
	{
		ArrayList<String> xCoords = new ArrayList<String>();
		ArrayList<String> yCoords = new ArrayList<String>();
		
		if (x > 0 && y < 10 && cells[x - 1][y] == 1)
		{
			xCoords.add(alphabet[x - 1] + Integer.toString(y));
		}
		
		if (x < 9 && y < 10 && cells[x + 1][y] == 1)
		{
			xCoords.add(alphabet[x + 1] + Integer.toString(y));
		}
		
		if (!xCoords.isEmpty()) return xCoords;
		
		if (y > 0 && x < 10 && cells[x][y - 1] == 1) 
		{
			yCoords.add(alphabet[x] + Integer.toString(y - 1));
		}
		
		if (y < 9 && x < 10 && cells[x][y + 1] == 1) 
		{
			yCoords.add(alphabet[x] + Integer.toString(y + 1));
		}
		
		if (!yCoords.isEmpty()) return yCoords;
		
		return xCoords;
	}
	
	public boolean cellCanBeShot(String coord, String excludeCoord)
	{
		int[] coords = Tools.convertStringCoordsToInt(coord);
		
		int xE, yE;
		
		if (excludeCoord != null)
		{
			int[] excludeCoords = Tools.convertStringCoordsToInt(excludeCoord);
			xE = excludeCoords[0];
			yE = excludeCoords[1];
		}
		else
		{
			xE = 100;
			yE = 100;
		}
		
		int x = coords[0]; 
		int y = coords[1];
		
		
		if (y > 0 && x > 0 && cells[x - 1][y - 1] == -1) return false; 
		
		if (y > 0 && cells[x][y - 1] == -1 
			          && x != xE 
				  && (y - 1) != yE) return false; 
				  
		if (y > 0 && x < 9 && cells[x + 1][y - 1] == -1) return false; 
		
		if (x < 9 && cells[x + 1][y] == -1 
				  && (x + 1) != xE 
				  && y != yE) return false; 
				  
		if (x < 9 && y < 9 && cells[x + 1][y + 1] == -1) return false; 
		
		if (y < 9 && cells[x][y + 1] == -1
				  && x != xE 
				  && (y + 1) != yE) return false; 
				  
		if (x > 0 && y < 9 && cells[x - 1][y + 1] == -1) return false; 
		
		if (x > 0 && cells[x - 1][y] == -1
				  && (x - 1) != xE 
				  && y != yE) return false; 
		
		return true;
	}
	
	private String coordToSink(String coord)
	{
		int[] coords = Tools.convertStringCoordsToInt(coord);
		int x = coords[0];
		int y = coords[1];
		int xNew;
		int yNew;
		
		AI ai = AI.getInstance();
		
		String newCoord;
		
		int k = 0;
		
		while (true)
		{
			int randDirection = (int) (Math.random() * 4);
			boolean coordsFound = false;
			System.out.println("Seeking for a right direction!!!");
			
			System.out.println("x: " + x);
			System.out.println("y:  " + y);
			
			xNew = 0;
			yNew = 0;
			
			k++;
			
			boolean endOfArea = false;
			
			switch (randDirection)
			{
				case 0:
					if (x > 0) 
					{
						System.out.println("Direction is 0");
						xNew = x - 1;
						yNew = y;
						coordsFound = true;
					}
					
					break;
				case 1:
					if (y > 0) 
					{
						System.out.println("Direction is 1");
						xNew = x;
						yNew = y - 1;
						coordsFound = true;
					}

					
					break;
				case 2:
					if (x != 9) 
					{
						System.out.println("Direction is 2");
						xNew = x + 1;
						yNew = y;
						coordsFound = true;
					}
					
					break;
				case 3:
					if (y != 9)
					{
						System.out.println("Direction is 3");
						xNew = x;
						yNew = y + 1;
						coordsFound = true;
					}
					break;
			}
			
			System.out.println("xNew: " + xNew);
			System.out.println("yNew: " + yNew);
			
			if (coordsFound)
			{
				newCoord = Tools.convertIntCoordsToString(xNew, yNew);
			
				if (!coordIsShot(newCoord) && cellCanBeShot(newCoord, coord)) break;
			}
		}
	
		return newCoord;
	}
	
	private ArrayList<ArrayList<String>> findAllOccupiedCellsInDirection(int x, int y)
	{
		ArrayList<String> neighbourCells = scanCellNeighbours(x, y);
		ArrayList<ArrayList<String>> occupiedCells = new ArrayList<ArrayList<String>>();
		ArrayList<String> occupiedCells1 = new ArrayList<String>();
		ArrayList<String> occupiedCells2 = new ArrayList<String>();
		
		int[] cellCoord1 = Tools.convertStringCoordsToInt(neighbourCells.get(0).toString());
		int[] cellCoord2 = Tools.convertStringCoordsToInt(neighbourCells.get(1).toString());

		//occupiedCells1.add(neighbourCells.get(0).toString());
		//occupiedCells2.add(neighbourCells.get(1).toString());
		
		// if direction is X
		if (cellCoord1[0] < x && cellCoord1[1] == y)
		{	
			while(true)
			{
				int stepX = cellCoord1[0]--;
				
				if (stepX >= 0)
				{
					if (cells[stepX][y] == 1)
					{
						occupiedCells1.add(Tools.convertIntCoordsToString(stepX, y));
					}
					else
					{
						break;
					}
				}
				else
				{
					break;
				}
			}
			
					
			while(true)
			{		
				int stepX = cellCoord2[0]++;
				
				if (stepX < 10)
				{
					if (cells[stepX][y] == 1)
					{
						
						occupiedCells2.add(Tools.convertIntCoordsToString(stepX, y));
					}
					else
					{
						break;
					}
				}
				else
				{
					break;
				}
			}
		}
			
		//if direction is Y
		if (cellCoord1[0] == x && cellCoord1[1] < y)
		{	
			int stepY;
				
			while(true)
			{
				stepY = cellCoord1[1]--;
				
				if (stepY >= 0)
				{
					if (cells[x][stepY] == 1)
					{
						occupiedCells1.add(Tools.convertIntCoordsToString(x, stepY));
					}
					else
					{
						break;
					}
				}
				else
				{
					break;
				}
			}
				
			while(true)
			{
				stepY = cellCoord2[1]++;

				if (stepY < 10)
				{
					if (cells[x][stepY] == 1)
					{
						occupiedCells2.add(Tools.convertIntCoordsToString(x, stepY));
					}
					else
					{
						break;
					}
				}
				else
				{
					break;
				}
			}
		}
		
		occupiedCells.add(occupiedCells1);
		occupiedCells.add(occupiedCells2);
		
		return occupiedCells;
	}	
}